package uni.stuttgart.openstreetmap;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Vector;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;


import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;


/*
 * PhotoBrowserActivity ist started by UserInterface
 * PhotoBrowserActivity get latitude and longitude boundary for photo search from the starting Intent
 * DownloadInformationTask downloads picture information like title, author and image address from panoramio and flickr
 * DownloadPictureTask loads images from panoramio or flickr when backward or forward button is clicked
 */
public class PhotoBrowserActivity extends Activity {
	
	private final double RADIUS_EARTH = 6371; //KM
	
	private final int PICTURE_LIMIT = 100;
	
	private volatile int shownPictureNumber = 0;
	private double startLatitude;
	private double startLongitude;
	private double endLatitude;
	private double endLongitude;
	
	private Vector<PhotoInformation> photoInformations;
	
	private Button pictureForward;
	private Button pictureBackward;
	
	private TextView textViewAuthor;
	private TextView textViewTitle;
	private TextView progressPercentage;
	
	private ProgressBar progressBar;
	
	private URL panoramioURL;
	private URL flickrURL;
	
	private FrameLayout pictureContainer;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_photo_browser);
		Intent i = getIntent();
		System.out.println("Intent i = "+i);
		initUI();
		if(savedInstanceState == null || (photoInformations = (Vector<PhotoInformation>)savedInstanceState.getSerializable("PHOTO_INFORMATIONS"))==null){
			
			/*Start values are top west
			Stop values are bottom east
			so we change them in URLs*/
			
			startLatitude = i.getExtras().getDouble("START_LATITUDE", 0.0);
			startLongitude = i.getExtras().getDouble("START_LONGITUDE", 0.0);
			endLatitude = i.getExtras().getDouble("END_LATITUDE", 0.0);
			endLongitude =  i.getExtras().getDouble("END_LONGITUDE", 0.0);
			
			System.out.println("startLatitude = " + startLatitude);
			System.out.println("startLongitude = " + startLongitude);
			System.out.println("endLatitude = " + endLatitude);
			System.out.println("endLongitude =  " + endLongitude);
			
			String panoramiaURLString = "http://www.panoramio.com/map/get_panoramas.php?" +
					"set=public&from=0&to=20" +
					"&minx="+startLongitude+"&miny="+endLatitude+
					"&maxx="+endLongitude+"&maxy="+startLatitude+"&size=medium&mapfilter=true";
			
			double flickrMapRadius = Math.abs(startLongitude-endLongitude)*Math.PI/180.0*RADIUS_EARTH;
			if(flickrMapRadius>32.0){
				flickrMapRadius = 32.0;
			}
			
			String flickrURLString = "http://api.flickr.com/services/rest?method=flickr.photos.search&" +
					"api_key=af132e1981a446a441e273025b302f64&" +
					"lat="+((startLatitude+endLatitude)/2.0)+"&lon="+((startLongitude+endLongitude)/2.0)+
					"&radius="+flickrMapRadius+"&accuracy=1&min_upload_date=1970-01-01";
			try {
				panoramioURL = new URL(panoramiaURLString);
				flickrURL = new URL(flickrURLString);
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
			
			loadInformation();
		}
		else{
			//photoInformations = (Vector<PhotoInformation>)savedInstanceState.getSerializable("PHOTO_INFORMATIONS");
			shownPictureNumber = savedInstanceState.getInt("SHOWN_PICTURE_NUMBER");
			if(photoInformations!=null){
				showPicture();
				pictureForward.setEnabled(true);
				pictureBackward.setEnabled(true);
			}
			
		}

	}
	
	
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		//TODO add null checks
		outState.putSerializable("PHOTO_INFORMATIONS", photoInformations);
		outState.putInt("SHOWN_PICTURE_NUMBER", shownPictureNumber);
		super.onSaveInstanceState(outState);
	}



	private void loadInformation() {
		System.out.println("loadInformation");
		new DownloadInformationTask().execute();
	}
	
	private void initUI() {
		textViewAuthor = (TextView) findViewById(R.id.text_view_author);
		textViewTitle = (TextView) findViewById(R.id.text_view_title);
		progressPercentage = (TextView) findViewById(R.id.progress_percentage);
		progressBar = (ProgressBar) findViewById(R.id.progressBar);
		
		pictureForward = (Button) findViewById(R.id.button_picture_forward);
		pictureForward.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				shownPictureNumber++;
				if(shownPictureNumber>(photoInformations.size()-1)){
					shownPictureNumber=0;
				}
				showPicture();
			}
		});
		
		pictureBackward = (Button) findViewById(R.id.button_picture_back);
		pictureBackward.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				shownPictureNumber--;
				if(shownPictureNumber<0){
					shownPictureNumber=photoInformations.size()-1;
				}
				showPicture();
			}
		});
		
		pictureContainer = (FrameLayout) findViewById(R.id.picture_layout);
		
		pictureForward.setEnabled(false);
		pictureBackward.setEnabled(false);
	}

	private void showPicture() {
		new DownloadPictureTask().execute(photoInformations); 
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.activity_photo_browser, menu);
		return false;
	}
	
	private class DownloadPictureTask extends AsyncTask<Vector<PhotoInformation>, Void, Bitmap> {
	     
		private static final int CONNECT_TIMEOUT = 2000;
		private static final int READ_TIMEOUT = 2000;

		@Override
		protected Bitmap doInBackground(Vector<PhotoInformation>... params) {
			URL tileUrl;
			HttpURLConnection connection = null;
			InputStream pictureInputStream =null;;
			Bitmap picture =null;
			try {
				tileUrl = new URL(params[0].get(shownPictureNumber).getPictureAdress());
				connection = (HttpURLConnection) tileUrl.openConnection();
				connection.setConnectTimeout(CONNECT_TIMEOUT);
				connection.setReadTimeout(READ_TIMEOUT);
				connection.connect();
				pictureInputStream = connection.getInputStream();
				picture = BitmapFactory.decodeStream(pictureInputStream);
			} catch (MalformedURLException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} 
			finally{
				//close connection
				
				if(pictureInputStream!=null){
					try {
						pictureInputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				
				if(connection!=null){
					connection.disconnect();
				}
			}
			
			return picture;
		}
		
		@Override
		protected void onPostExecute(Bitmap result) {
			textViewTitle.setText(photoInformations.get(shownPictureNumber).getTitle());
			textViewAuthor.setText(photoInformations.get(shownPictureNumber).getAuthor());
			ImageView iv = new ImageView(PhotoBrowserActivity.this);
			iv.setImageBitmap(result);
			pictureContainer.removeAllViews();
			pictureContainer.addView(iv);
		}

	 }
	
	private class DownloadInformationTask extends AsyncTask<Void, Integer, Vector<PhotoInformation>>{

		private int counter;
		private int q = 0;
		private int w = 0;
		private int pictureCount;
		
		private Vector<PhotoInformation> photos;
		
		private JSONObject jsonObject;
		private JSONArray jsonArray;
		private SAXParserFactory factory;
		private SAXParser parser;

		private Vector<String> flickrPhotoIDs;
		private Vector<String> flickrSecrets;
		private Vector<String> flickrTitles;
		private Vector<String> flickrAuthors;
		private Vector<String> flickrAdresses;
		private PhotoSearchHandler saxHandlerSearch;
		private PhotoInformationHandler saxHandlerPhoto;
		private PhotoPayloadHandler saxPayloadHandler;
		
		private StringBuffer sb;
		
		
		
		@Override
		protected void onPreExecute() {
			progressBar.setVisibility(View.VISIBLE);
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			progressBar.setProgress(values[0]);
			String str = Integer.toString(values[0])+"%";
			progressPercentage.setText(str);
		}

		@Override
		protected Vector<PhotoInformation> doInBackground(Void... params) {
			
			System.out.println("doInBackground DownloadInformationTask");
			
			photos = new Vector<PhotoInformation>();
			
			try{
				downloadInformationFromPanoramio();
				
				flickrPhotoIDs = new Vector<String>();
				flickrSecrets = new Vector<String>();
				flickrAuthors = new Vector<String>();
				flickrTitles = new Vector<String>();
				flickrAdresses = new Vector<String>();
				
				downloadInformationFromFlickr();
				
				pictureCount = jsonArray.length() + flickrPhotoIDs.size();
				
				System.out.println("before picturecount = "+ pictureCount);
				
				if(pictureCount>PICTURE_LIMIT){
					pictureCount=PICTURE_LIMIT;
				}
				
				if(pictureCount<1){
					return null;
				}
				
				System.out.println("picturecount = "+ pictureCount);
				
				boolean toggle = true;
				q=0;
				w=0;
				
				for(counter = 0;counter <pictureCount;counter++){
					
					if(toggle){
						if(q<jsonArray.length()){
							JSONObject obj = (JSONObject)jsonArray.opt(q);
							photos.add(new PhotoInformation(
										obj.getString("owner_name"),
										obj.getString("photo_title"),
										obj.getString("photo_file_url")));
							q++;
						}
						toggle = !toggle;
					}
					else{
						if(w<flickrPhotoIDs.size()){
						
							sb = new StringBuffer();
							
							String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodCall><methodName>flickr.photos.getInfo</methodName><params><param><value><struct><member><name>secret</name><value>"+flickrSecrets.get(w)+"</value></member><member><name>photo_id</name><value>"+flickrPhotoIDs.get(w)+"</value></member><member><name>api_key</name><value>af132e1981a446a441e273025b302f64</value></member></struct></value></param></params></methodCall>";

							URL flickrURL = new URL("http://api.flickr.com/services/xmlrpc");
							HttpURLConnection connection = (HttpURLConnection) flickrURL.openConnection();

							connection.setDoOutput(true);
							connection.setDoInput(true);
							connection.setRequestMethod("POST");

							OutputStream out = connection.getOutputStream();
							OutputStreamWriter outw = new OutputStreamWriter(out, "UTF-8");
							outw.write(request);
							outw.flush();

							InputStream in = connection.getInputStream();
						
							
							saxPayloadHandler = new PhotoPayloadHandler();
							parser.parse(in, saxPayloadHandler);
							
							sb.trimToSize();
							
							
							saxHandlerPhoto = new PhotoInformationHandler();
							parser.parse(new InputSource(new StringReader(sb.toString().trim())), saxHandlerPhoto);
								
							
							
							in.close();
							out.close();
							connection.disconnect();
								
								
								photos.add(new PhotoInformation(flickrAuthors.get(w), flickrTitles.get(w), flickrAdresses.get(w)));
								
							
							
								w++;
						}
						toggle = !toggle;
					}
					publishProgress((int) ((counter / (float) pictureCount) * 100));
					
				}
				
			}catch(IOException e){
				e.printStackTrace();
			}  catch (JSONException e) {
				e.printStackTrace();
			} catch (ParserConfigurationException e) {
				e.printStackTrace();
			} catch (SAXException e) {
				e.printStackTrace();
			} 
			
			return photos;
		}
		
		private void downloadInformationFromPanoramio() throws IOException, JSONException{
			
				HttpURLConnection urlConnection = (HttpURLConnection) panoramioURL.openConnection();
				BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
				StringBuffer stb = new StringBuffer();
				String line;
				while((line=br.readLine())!=null){
					stb.append(line);
				}
				jsonObject = new JSONObject(stb.toString());
				jsonArray = jsonObject.getJSONArray("photos"); 
			
		}
		
		private void downloadInformationFromFlickr() throws ParserConfigurationException, SAXException, IOException{

			HttpURLConnection urlConnection = (HttpURLConnection) flickrURL.openConnection();
			factory = SAXParserFactory.newInstance();
			parser = factory.newSAXParser();
			saxHandlerSearch = new PhotoSearchHandler();
			parser.parse(urlConnection.getInputStream(), saxHandlerSearch);
		}
		
		@Override
		protected void onPostExecute(Vector<PhotoInformation> result) {
			progressBar.setVisibility(View.GONE);
			progressPercentage.setVisibility(View.GONE);
			photoInformations = result;
			if(photoInformations!=null){
				showPicture();
				pictureForward.setEnabled(true);
				pictureBackward.setEnabled(true);
			}
		}
		
		private class PhotoSearchHandler extends DefaultHandler {
			public void startElement(String uri,String localName, String qName,org.xml.sax.Attributes attributes) {
				
				if(localName.equals("photo")){
					flickrPhotoIDs.add(attributes.getValue("id"));
					flickrSecrets.add(attributes.getValue("secret"));
					flickrTitles.add(attributes.getValue("title"));
				}
			}
		}

		private class PhotoInformationHandler extends DefaultHandler {
			
			public void startElement(String uri,String localName, String qName,org.xml.sax.Attributes attributes) {
				
				if(localName.equals("photo")){
					String photoAdress = "http://farm"+attributes.getValue("farm")+".static.flickr.com/" +
							attributes.getValue("server")+"/"+attributes.getValue("id")+"_"+attributes.getValue("secret")+".jpg";
					
					flickrAdresses.add(photoAdress);

				}else if(localName.equals("owner")){
					flickrAuthors.add(attributes.getValue("username"));
				}
			}

			@Override
			public void characters(char[] ch, int start, int length) throws SAXException {
				
				for(int i=start;i<(start+length);i++  ){
					sb.append(ch[i]);
				}
			}
			
			
		}
		
			private class PhotoPayloadHandler extends DefaultHandler {

			@Override
			public void characters(char[] ch, int start, int length)
					throws SAXException {
				
				
				for(int i=start;i<(start+length);i++  ){
					sb.append(ch[i]);
				}
			}
		}
	}
}
